Проведем исследование для инвесторов из фонда «Shut Up and Take My Money». Наша задача проанализировать рынок заведений общественного питания Москвы. Наша цель - Помочь заказчику определиться с открытием заведения общественного питания
Нам доступен датасет с заведениями общественного питания Москвы, составленный на основе данных сервисов Яндекс Карты и Яндекс Бизнес на лето 2022 года. Информация, размещённая в сервисе Яндекс Бизнес, могла быть добавлена пользователями или найдена в общедоступных источниках. Она носит исключительно справочный характер.
Поэтому мы должны провести следующие действия:
Приступим к выполнению задачи.
Для начала загрузим и обновим все необходимые для работы и визуализаций библиотеки
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from folium import Map, Marker, Choropleth
from folium.plugins import MarkerCluster
import plotly.express as px
import plotly.graph_objects as go
import json
А также зададим общий стиль всем выводимым графикам, чтобы в дальнейшем представить графики в качестве презентации.
sns.set_style(style='ticks') #Задать общий размер фигур не получилось, все время съезжало форматирование
sns.set_context('talk') #Через раз съезжает, видимо из-за индивидуальных настроек каждого графика
Загрузим все имеющиеся у нас данные:
moscow_places со всей информацией о Московских общепитахadmin_level_geomappath = 'D:\\Irina\\datasets\\'
moscow_places = pd.read_csv(path + 'moscow_places.csv')
with open(path + 'admin_level_geomap.geojson', 'r', encoding='utf-8') as f:
geo_json = json.load(f)
#Зададим ограничения на вывод колонок и количество символов - в данном случае "смягчим"
pd.set_option('display.max_columns', None)
pd.options.display.max_colwidth = 100
moscow_places.head()
| name | category | address | district | hours | lat | lng | rating | price | avg_bill | middle_avg_bill | middle_coffee_cup | chain | seats | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | WoWфли | кафе | Москва, улица Дыбенко, 7/1 | Северный административный округ | ежедневно, 10:00–22:00 | 55.878494 | 37.478860 | 5.0 | NaN | NaN | NaN | NaN | 0 | NaN |
| 1 | Четыре комнаты | ресторан | Москва, улица Дыбенко, 36, корп. 1 | Северный административный округ | ежедневно, 10:00–22:00 | 55.875801 | 37.484479 | 4.5 | выше среднего | Средний счёт:1500–1600 ₽ | 1550.0 | NaN | 0 | 4.0 |
| 2 | Хазри | кафе | Москва, Клязьминская улица, 15 | Северный административный округ | пн-чт 11:00–02:00; пт,сб 11:00–05:00; вс 11:00–02:00 | 55.889146 | 37.525901 | 4.6 | средние | Средний счёт:от 1000 ₽ | 1000.0 | NaN | 0 | 45.0 |
| 3 | Dormouse Coffee Shop | кофейня | Москва, улица Маршала Федоренко, 12 | Северный административный округ | ежедневно, 09:00–22:00 | 55.881608 | 37.488860 | 5.0 | NaN | Цена чашки капучино:155–185 ₽ | NaN | 170.0 | 0 | NaN |
| 4 | Иль Марко | пиццерия | Москва, Правобережная улица, 1Б | Северный административный округ | ежедневно, 10:00–22:00 | 55.881166 | 37.449357 | 5.0 | средние | Средний счёт:400–600 ₽ | 500.0 | NaN | 1 | 148.0 |
Итак, мы сохранили все данные в датасет. У нас есть следующие колонки:
name — название заведения;category — категория заведения, например «кафе», «пиццерия» или «кофейня»;address — адрес заведения;district — административный район, в котором находится заведение, например Центральный административный округ;hours — информация о днях и часах работы;lat — широта географической точки, в которой находится заведение;lng — долгота географической точки, в которой находится заведение;rating — рейтинг заведения по оценкам пользователей в Яндекс Картах (высшая оценка — 5.0);price — категория цен в заведении, например «средние», «ниже среднего», «выше среднего» и так далее;avg_bill — строка, которая хранит среднюю стоимость заказа в виде диапазона, например:middle_avg_bill — число с оценкой среднего чека, которое указано только для значений из столбца avg_bill, начинающихся с подстроки «Средний счёт»:middle_coffee_cup — число с оценкой одной чашки капучино, которое указано только для значений из столбца avg_bill, начинающихся с подстроки «Цена одной чашки капучино»:chain — число, выраженное 0 или 1, которое показывает, является ли заведение сетевым (для маленьких сетей могут встречаться ошибки):seats — количество посадочных мест.print('В датасете представлено {} уникальных заведений'.format(moscow_places['name'].nunique()),
'\nВсего в датасете {} заведений'.format(moscow_places['name'].count()))
В датасете представлено 5614 уникальных заведений Всего в датасете 8406 заведений
Итак, в нашем датасете есть записи о 8406 заведениях общественного питания, из них 5614 уникальных заведений по названию. Возможно в Москве преобладают несетевые заведения, оценим это позже.
moscow_places.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 8406 entries, 0 to 8405 Data columns (total 14 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 name 8406 non-null object 1 category 8406 non-null object 2 address 8406 non-null object 3 district 8406 non-null object 4 hours 7870 non-null object 5 lat 8406 non-null float64 6 lng 8406 non-null float64 7 rating 8406 non-null float64 8 price 3315 non-null object 9 avg_bill 3816 non-null object 10 middle_avg_bill 3149 non-null float64 11 middle_coffee_cup 535 non-null float64 12 chain 8406 non-null int64 13 seats 4795 non-null float64 dtypes: float64(6), int64(1), object(7) memory usage: 919.5+ KB
Из полученной информации о датасете можно сделать следующие выводы:
Теперь займёмся предобработкой наших данных, чтобы было проще работать.
Изучим подробнее пропуски в столбцах и исследуем есть ли у нас дубликаты в данных.
Начнём с пропусков, выясним:
#Сделаем новую таблицу, чтобы удобнее было тонко настраивать график
data_skips = ((moscow_places.isna().mean()*100)
.to_frame()
.rename(columns = {0:'space'})
.query('space > 0')
.sort_values(by = 'space', ascending = True))
#строим график, который будет визуализировать только пропуски
(data_skips.plot(kind = 'barh',
figsize = (19,8),
rot = 0,
legend = False,
color = '#66CDAA',
fontsize = 16)
.set_title('Количество пропусков в колонках' + "\n", fontsize = 22, color = 'SteelBlue'))
plt.xlabel('Процент пропущенных значений, %', fontsize = 16)
plt.ylabel('Колонки, в котрых есть пропуски', fontsize = 16)
#Чтобы вывести на график проценты пропусков для наглядности
rects = plt.barh(np.arange(len(data_skips.space)),data_skips.space,0)
plt.bar_label(rects,fontsize = 16,fmt = '%.2f%%')
#добавим линию в районе среднего значения пропусков и подпишем
plt.vlines(x = data_skips.space.mean(), ymin = -0.5, ymax = 5.5, ls='--',colors ='red', lw = 3)
plt.text(data_skips.space.mean() + 0.5, 1,
f'Среднее значение: {round(data_skips.space.mean(),2)}%',fontsize = 16)
plt.show()
Согласно полученному графику и информации ранее в датасете есть много пропусков, в среднем в колонках около 53.5% пропусков. Это очень много. У нас есть пропуски в 6 из 14 колонках:
middle_coffee_cup - сюда попадают значения, в зависимости от значений из колонки avg_bill, однако, и в колонке avg_bill есть много пропусков и не всегда есть строка "Цена одной чашки капучино". Возможно заведение не продаёт кофе, или просто они нигде не указали стоимость чашки кофе. К сожалению, в колонке почти 94% пропусков, а значит удалить строки с пропусками мы не можем. А также нет логичных способов восполнить существующие пропуски.middle_avg_bill - эта колонка также зависит от значений, указанных в колонке avg_bill. И опять же - либо это связано с пропусками в колонке avg_bill, или не встречается строка "Средний счёт". И в этом случае также трудно осуществить логичную замену.price - возможно значения в этой колонке зависят от колонки middle_avg_bill, но скорее всего просто не всегда указываются.avg_bill - содержит 55% пропусков. В колонке содержатся разные значения для разных типов заведений. Предсказать эти значения мы не можем.seats - уже менее 50% пропусков, возможно это заведения, которые работают только навынос или расположены в торговых центрах и не имеют своих "закрепленных" мест, или же просто не указаны владельцами.hours - всего 6% пропусков, меньше всего во всём датасете. Но и здесь мы не можем узнать, как нам решить эту проблему и что является её причиной.Итак, у нас есть очень много пропусков, которые нам неподвластны, придётся работать с тем, что есть, возможно это не повлияет на наш анализ. К сожалению, это часто происходит с общедоступными данными, которые заполняются в свободой форме любым желающим.
print('В датасете {} полных явных дубликатов'.format(moscow_places.duplicated().sum()))
В датасете 0 полных явных дубликатов
Итак, полных явных дубликатов нет, значит в сервисах Яндекс.Карты и Яндекс.Бизнес есть механизм, позволяющий избавляться от дублирующейся информации.
Теперь проверим, нет ли неполных дубликатов.
#Проверим в связке имя-адрес
print('В датасете {} неполных дубликатов'.format(moscow_places.duplicated(subset=['name',
'address']).sum()))
В датасете 0 неполных дубликатов
#Приведём все названия к нижнему регистру и проверим снова
moscow_places['name'] = moscow_places['name'].str.lower()
print('В датасете {} неполных дубликата'.format(moscow_places.duplicated(subset=['name',
'address']).sum()))
В датасете 3 неполных дубликата
Посмотрим, что это за дубликаты.
moscow_places.value_counts(subset=['name','address']).head(5)
name address хлеб да выпечка Москва, Ярцевская улица, 19 2 раковарня клешни и хвосты Москва, проспект Мира, 118 2 more poke Москва, Волоколамское шоссе, 11, стр. 2 2 навруз Москва, Новоясеневский проспект, 1Б, корп. 2 1 на углях Москва, 5-я Кабельная улица, 8 1 dtype: int64
У нас есть три неполных дупликата, удалим их, оставив первые записи.
moscow_places = moscow_places.drop_duplicates(subset=['name','address'], keep = 'first')
print('В датасете {} неполных дубликатов'.format(moscow_places.duplicated(subset=['name',
'address']).sum()))
В датасете 0 неполных дубликатов
print('В датасете осталось {} уникальных заведений'.format(moscow_places['name'].nunique()),
'\nВсего в датасете осталось {} заведений'.format(moscow_places['name'].count()))
В датасете осталось 5512 уникальных заведений Всего в датасете осталось 8403 заведений
Итак, при приведении названий заведений к нижнему регистру у нас уменьшилось число уникальных заведений, возможно таким образом нам удалось избавиться от неявных дубликатов, или в Москве много мест с похожими названиями, которые отличались регистром.
Всего из датасета мы удалили три строки, а это менее половины процента данных - 0.04%.
К сожалению, мы не можем полностью проверить наличие неявных дубликатов, так как в нашем датасете хранится информация о 5512 уникальных заведениях. А значит будет трудно найти и обработать возможные опечатки и ошибки. Затраты времени на автоматизацию поиска такого рода аномалий в настоящий момент необоснованы.
Поэтому примем, что в наших данных нет неявных дубликатов и приступим к дальнейшей обработке данных.
Для простоты работы с данными добавим несколько столбцов:
street с названиями улиц;is_24/7 с указанием, является ли заведение круглосуточным.Эти столбцы нам потребуются для дальнейшего анализа.
#Разбиваем значения колонки address по запятым и получаем второе значение, соответствующее улице
moscow_places['street'] = moscow_places['address'].str.split(',').str[1]
#Выберем заведения, которые работают круглосуточно и ежедневно, за исключением строк,
#где не указано время работы, и присвоим значение True,
#В противном случае - False
moscow_places['is_24/7'] = np.where(moscow_places['hours'].notnull()
& (moscow_places['hours'].str.contains('круглосуточно')
& moscow_places['hours'].str.contains('ежедневно')),
True, False)
moscow_places.sample(5)
| name | category | address | district | hours | lat | lng | rating | price | avg_bill | middle_avg_bill | middle_coffee_cup | chain | seats | street | is_24/7 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 7158 | столовая uz | быстрое питание | Москва, Каширское шоссе, 9, корп. 3 | Южный административный округ | ежедневно, 08:00–23:00 | 55.668640 | 37.631110 | 4.3 | средние | Средний счёт:100–500 ₽ | 300.0 | NaN | 0 | 160.0 | Каширское шоссе | False |
| 6068 | elephantkids | кафе | Москва, улица Орджоникидзе, 12, стр. 4 | Южный административный округ | пн-пт 10:00–18:00 | 55.710240 | 37.590704 | 4.1 | NaN | NaN | NaN | NaN | 0 | 0.0 | улица Орджоникидзе | False |
| 3248 | додо пицца | пиццерия | Москва, Малая Филёвская улица, 14А | Западный административный округ | ежедневно, 08:00–23:00 | 55.737760 | 37.470779 | 4.3 | NaN | NaN | NaN | NaN | 1 | 52.0 | Малая Филёвская улица | False |
| 3412 | брусника | кафе | Москва, улица Пресненский Вал, 3 | Центральный административный округ | ежедневно, 08:00–23:00 | 55.765499 | 37.563944 | 4.6 | NaN | NaN | NaN | NaN | 1 | 30.0 | улица Пресненский Вал | False |
| 273 | pho oanh | кафе | Москва, Староватутинский проезд, 14 | Северо-Восточный административный округ | ежедневно, 11:00–21:30 | 55.875804 | 37.665551 | 4.0 | NaN | NaN | NaN | NaN | 1 | 100.0 | Староватутинский проезд | False |
Отлично, два новых столбца добавлены, теперь мы можем приступить к анализу данных.
Теперь приступим к анализу наших данных:
Мы уже знаем сколько заведений представлено в данных, теперь узнаем, какие конкретно заведения встречаются в Москве. В нашей базе данных есть колонка category, которая хранит информацию, к какому типу относится то или иное заведение. Проведем исследования количества типов объектов и подробной информации о каждом типе.
#Создадим датафрейм для типов заведений, для каждого типа:
#найдем количество заведений, среднее количество мест, средний рейтинг и являются ли они сетевыми
category_data = (pd.pivot_table(moscow_places,
index='category',
values=['name','seats','rating','chain'],
aggfunc={'name':'count',
'seats':'median',
'rating':'mean',
'chain':'sum'})
.sort_values(by='name',ascending=False))
#Добавим недостающие столбцы
category_data['not_chain'] = category_data['name']-category_data['chain']
#Почему-то съехала последовательность столбцов, пришлось насильно поправить
category_data = category_data[['name','rating','seats','chain','not_chain']]
#Округлим рейтинг
category_data['rating'] = category_data['rating'].round(1)
category_data = category_data.reset_index()
category_data
| category | name | rating | seats | chain | not_chain | |
|---|---|---|---|---|---|---|
| 0 | кафе | 2377 | 4.1 | 60.0 | 779 | 1598 |
| 1 | ресторан | 2042 | 4.3 | 86.0 | 729 | 1313 |
| 2 | кофейня | 1413 | 4.3 | 80.0 | 720 | 693 |
| 3 | бар,паб | 764 | 4.4 | 82.0 | 168 | 596 |
| 4 | пиццерия | 633 | 4.3 | 55.0 | 330 | 303 |
| 5 | быстрое питание | 603 | 4.1 | 65.0 | 232 | 371 |
| 6 | столовая | 315 | 4.2 | 75.5 | 88 | 227 |
| 7 | булочная | 256 | 4.3 | 50.0 | 157 | 99 |
У нас всего есть 8 типов заведений:
Для начала изучим, как много заведений каждого типа представлено в файле.
plt.figure(figsize=(10,8))
sns.barplot(data = category_data, y='category',x='name', orient='h').set(ylabel='Тип заведения',
xlabel='Количество заведений')
plt.title('Количество заведений по типу', fontsize=20, color='SteelBlue')
plt.show();
кафе, на втором месте - ресторан, на третьем месте - кофейня. В данных категориях встречается не менее 1000 заведений, в среднем их более 1500 тысяч. бар/паб, пиццерия, быстрое питание. столовых и булочных - каждая из этих категорий насчитывает менее 500 заведений.Теперь оценим, сколько в среднем посадочных мест приходится на каждый тип заведения.
plt.figure(figsize=(10,8))
sns.barplot(data = category_data.sort_values(by='seats'),
y='category',x='seats', orient='h').set(ylabel='Тип заведения', xlabel='Количество мест')
plt.title('Среднее количество мест в зависмости от категории', fontsize=20, color='SteelBlue');
Мы отметили, что из 8403 записей у нас есть 5512 заведений с уникальными наименованиями и сделали предположение, что в Москве преобладают несетевые заведения. Настало время проверить эту теорию.
is_chain = pd.DataFrame({'type': moscow_places['chain'].value_counts().index,
'total': moscow_places['chain'].value_counts().values})
is_chain['type'] = is_chain['type'].replace({0: 'Несетевые', 1: 'Сетевые'})
plt.figure(figsize=(8,8))
plt.pie(data=is_chain, x='total', autopct='%.0f%%');
plt.legend(labels=is_chain['type'], loc='best')
plt.title('Соотношение сетевых и несетевых заведений', fontsize=20, color='SteelBlue')
plt.show()
Действительно, 62% заведений в Москве не относятся ни к одной сети. Рассмотрим подробнее, среди каких типов заведений чаще встречаются сетевые.
ax = category_data.plot(kind='barh',stacked=True, x='category', y=['not_chain','chain'], xlabel='Тип заведения', figsize=(15,8))
for i in ax.containers:
ax.bar_label(i,label_type='center')
ax.set_xlabel('Количество заведений')
ax.set_title('Сетевые заведения по типу заведения', fontsize=20, color='SteelBlue')
ax.legend(labels=['Не сетевые','Сетевые']);
Оценим, есть ли различия в средних рейтингах в зависимости от типа заведения.
fig, axes = plt.subplots(1, 2, figsize=(15, 5), sharey=True);
plt.figure(figsize=(10,8));
fig.suptitle('Среднее рейтинг заведений в зависмости от категории', fontsize=20, color='SteelBlue');
sns.barplot(ax=axes[0], data = category_data.sort_values(by='rating'),
y='category',x='rating',orient='h').set(ylabel='Тип заведения', xlabel='Значение рейтинга');
axes[0].set_xlim(0,5);
sns.barplot(ax=axes[1], data = category_data.sort_values(by='rating'),
y='category',x='rating',orient='h').set(ylabel='',xlabel='Значение рейтинга');
axes[1].set_xlim(4,5);
axes[1].set_xticks(np.arange(4,5, step = 0.1), minor=True);
for i in axes[1].containers:
axes[1].bar_label(i,)
plt.show();
<Figure size 1000x800 with 0 Axes>
Значения среднего рейтинга почти не различаются для заведений разных категорий. Средний рейтинг, в основном превышает 4 балла из 5 возможных. Однако, с небольшим отрывом, лидируют всё же бары и пабы.
Теперь проанализируем наши сетевые заведения. Выведем самые многочисленные сети в Москве и разберем, чем они отличаются, а также что у них общего.
top_chains = (moscow_places.query('chain == 1')
.pivot_table(index='name',
values=['address','category','price'],
aggfunc={'address':'count','category':'first','price':'first'})
.sort_values(by='address', ascending=False)
.reset_index())
top_chains = top_chains.head(15)
top_chains
| name | address | category | price | |
|---|---|---|---|---|
| 0 | шоколадница | 120 | кофейня | средние |
| 1 | домино'с пицца | 76 | пиццерия | средние |
| 2 | додо пицца | 74 | пиццерия | средние |
| 3 | one price coffee | 71 | кофейня | средние |
| 4 | яндекс лавка | 69 | ресторан | None |
| 5 | cofix | 65 | кофейня | средние |
| 6 | prime | 50 | ресторан | низкие |
| 7 | хинкальная | 44 | быстрое питание | средние |
| 8 | кофепорт | 42 | кофейня | низкие |
| 9 | кулинарная лавка братьев караваевых | 39 | кафе | средние |
| 10 | теремок | 38 | ресторан | средние |
| 11 | чайхана | 37 | кафе | средние |
| 12 | cofefest | 32 | кофейня | средние |
| 13 | буханка | 32 | булочная | средние |
| 14 | му-му | 27 | кафе | средние |
Визуализируем полученную таблицу.
plt.figure(figsize=(10,8))
sns.barplot(data=top_chains, x='address', y='name', orient = 'h', palette = 'summer')
plt.xlabel('Количество заведений')
plt.ylabel('Название сети')
plt.title('Топ-15 популярных сетевых заведений', fontsize=20, color='SteelBlue');
Шоколадница - в Москве насчитывается 120 заведений данной сети - это кофейня, которая кроме кофе также подаёт еду различной кухни, а также предоставляет возможность заказать комбинированные блюда по фиксированной цене.Домино'с Пицца, Додо Пицца, One Price Coffee, Яндекс.Лавка и Cofix - они насчитывют от 60 до 80 заведений. Можно заметить, что в основном это пиццерии и кофейни, которые работают в основном на вынос, кроме Яндекс.Лавки;Prime, Хинкальная и КОФЕПОРТ;Кулинарная лавка братьев Краваевых, Теремок, Чайхана, CofeFest, Буханка, Му-Му.Самые популярные сети в Москве насчитывают более 20 заведений по городу, теперь посмотрим, к каким категориям они относятся.
top_category = top_chains.groupby('category')['address'].sum().to_frame()
plt.figure(figsize=(8,8))
plt.pie(data=top_category, x='address',autopct='%.0f%%', colors=['#751A33','#B34233','#D28F33','#D4B95E','#4EA2A2','#1A8693']);
#Чтобы легенда не перекрывала график
plt.legend(bbox_to_anchor = (1,1), labels=top_category.index)
plt.title('Доля заведений среди топ-15 сетей по категории', fontsize=20, color='SteelBlue')
plt.show()
Большую долю среди сетевых заведений занимают кофейни, но скорее всего это связано с тем, что самая популярная сеть Шоколадница, имеющая больше всего торговых точек, является кофейней. Затем примерно одинаковые доли занимают рестораны и пиццерии. После них идут кафе. Ну и самые маленькие доли, менее 10% от всех заведений, занимают сети быстрого питания и булочные.
Теперь посмотрим, какая ценовая политика характерна для этих заведений.
plt.figure(figsize=(8,8))
sns.barplot(data = top_chains.groupby('price')['address'].sum().to_frame().reset_index(),
x='price',
y='address').set(xlabel='Уровень цен',
ylabel='Количество заведений')
plt.title('Средний уровень цен в 15 популярных сетях', fontsize=20, color='SteelBlue');
В основном в популяных сетевых заведениях средние цены, реже низкие. Исключение составляет Яндекс.Лавка, но она скорее представляет собой агрегатор, так что нельзя точно установить ценовой диапазон для этой сети.
Посмотрим, что понимается под "средними" ценами.
moscow_places.query('price =="средние"')['middle_avg_bill'].describe()
count 1668.000000 mean 598.908273 std 294.840114 min 165.000000 25% 350.000000 50% 500.000000 75% 850.000000 max 2150.000000 Name: middle_avg_bill, dtype: float64
Из полученных данных мы можем сделать вывод, что "средними" можно считать цены за средний чек от 350 до 1000 рублей - выше и ниже этого диапазона могут быть выбросы. Но скорее всего значения среднего чека разнятся от типа заведения, а также мы не можем точно сказать как формируются значения столбца price, возможно они указываются самими хозяевами заведений по их усмотрению.
Принимая во внимание указанные поправки будем считать "средними" цены от 350 до 1000 рублей.
Теперь рассмотрим, в каких административных районах Москвы - Округах, расположены исследуемые заведения и какие закономерности в зависимости от расположения мы можем рассмотреть.
district_data = pd.pivot_table(moscow_places,
index='district',
columns = 'category',
values='name',
aggfunc='count')
#общее число заведений в округе
district_data['total'] = district_data.sum(axis=1)
#Средний рейтинг по округам
district_data = district_data.merge(moscow_places.groupby('district')['rating'].median()
.reset_index(),on='district').sort_values(by='total', ascending = False)
district_data
| district | бар,паб | булочная | быстрое питание | кафе | кофейня | пиццерия | ресторан | столовая | total | rating | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 5 | Центральный административный округ | 364 | 50 | 87 | 464 | 428 | 113 | 670 | 66 | 2242 | 4.4 |
| 2 | Северный административный округ | 68 | 39 | 58 | 235 | 193 | 77 | 188 | 41 | 899 | 4.3 |
| 8 | Южный административный округ | 68 | 25 | 85 | 264 | 131 | 73 | 202 | 44 | 892 | 4.3 |
| 3 | Северо-Восточный административный округ | 62 | 28 | 82 | 269 | 159 | 68 | 182 | 40 | 890 | 4.2 |
| 1 | Западный административный округ | 50 | 37 | 62 | 238 | 150 | 71 | 218 | 24 | 850 | 4.3 |
| 0 | Восточный административный округ | 53 | 25 | 71 | 272 | 105 | 72 | 160 | 40 | 798 | 4.3 |
| 6 | Юго-Восточный административный округ | 38 | 13 | 67 | 282 | 89 | 55 | 145 | 25 | 714 | 4.2 |
| 7 | Юго-Западный административный округ | 38 | 27 | 61 | 238 | 96 | 64 | 168 | 17 | 709 | 4.3 |
| 4 | Северо-Западный административный округ | 23 | 12 | 30 | 115 | 62 | 40 | 109 | 18 | 409 | 4.3 |
Всего в нашем датасете есть 9 административных округов, нехватает трех:
Несмотря на то, что они юридически считаются частью Москвы, скорее всего мы их не учитываем из-за удаленности от МКАДа, или иных, неизвестных нам причин.
plt.figure(figsize=(19,8))
sns.barplot(data=district_data,
y='district',
x='total',
orient='h').set(xlabel='Количество заведений', ylabel='Округ')
plt.title('Распределение заведений по округам', fontsize=20, color = 'SteelBlue')
plt.show()
Теперь оценим, какие типы заведений характерны для каждого округа.
#Чтобы подписи были красивые
tick_labels = ['ЦАО','САО','ЮАО','СВАО','ЗАО','ВАО','ЮВАО','ЮЗАО','СЗАО']
district_data[['district',
'бар,паб',
'булочная',
'быстрое питание',
'кафе','кофейня',
'пиццерия',
'ресторан',
'столовая']].set_index('district').plot.bar(xlabel='Округ',
figsize=(20,9),
stacked=True,
rot = 0)
plt.ylabel('Количество заведений')
#уберем страшные длинные названия из подписей без нагромождения дополнительных столбцов в таблице
plt.xticks(ticks=[0,1,2,3,4,5,6,7,8],labels=tick_labels)
plt.title('Количество заведений в зависимости от типа в разрезе округов Москвы',
fontsize = 20, color='SteelBlue')
plt.show()
кафе и ресторанов, при чем кафе лидирует по количеству заведений. кофеен - например в ЗАО, САО, СВАО и ЮАО.столовых и булочныхрестораны, в этом округе они опережают кафе. Скорее всего это связано с тем, что в центре столицы предпочтение отдается заведениям, где можно спокойно посидеть и насладиться видами и архитектурой. Также это может быть связано с высоким туристическим потоком в данном районе.бары и пабы, скорее всего потому, что центр города больше представляет собой развлекательную/прогулочную/офисную часть города и здесь почти нет жилых зданий. Поэтому для питейных заведений здесь меньше ограничений.Оценим, как расположение заведений влияет на средний рейтинг. Для этого построим карту Москвы и укажем на ней фоновую картограмму (Хороплет) со средним рейтингом заведений каждого округа.
district_data
| district | бар,паб | булочная | быстрое питание | кафе | кофейня | пиццерия | ресторан | столовая | total | rating | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 5 | Центральный административный округ | 364 | 50 | 87 | 464 | 428 | 113 | 670 | 66 | 2242 | 4.4 |
| 2 | Северный административный округ | 68 | 39 | 58 | 235 | 193 | 77 | 188 | 41 | 899 | 4.3 |
| 8 | Южный административный округ | 68 | 25 | 85 | 264 | 131 | 73 | 202 | 44 | 892 | 4.3 |
| 3 | Северо-Восточный административный округ | 62 | 28 | 82 | 269 | 159 | 68 | 182 | 40 | 890 | 4.2 |
| 1 | Западный административный округ | 50 | 37 | 62 | 238 | 150 | 71 | 218 | 24 | 850 | 4.3 |
| 0 | Восточный административный округ | 53 | 25 | 71 | 272 | 105 | 72 | 160 | 40 | 798 | 4.3 |
| 6 | Юго-Восточный административный округ | 38 | 13 | 67 | 282 | 89 | 55 | 145 | 25 | 714 | 4.2 |
| 7 | Юго-Западный административный округ | 38 | 27 | 61 | 238 | 96 | 64 | 168 | 17 | 709 | 4.3 |
| 4 | Северо-Западный административный округ | 23 | 12 | 30 | 115 | 62 | 40 | 109 | 18 | 409 | 4.3 |
# создаём карту Москвы
m = Map(location=[55.751244, 37.618423], tiles='Cartodb Positron')
Choropleth(
geo_data=geo_json,
data=district_data,
columns=['district', 'rating'],
key_on='properties.name',
fill_color='YlGn',
fill_opacity=0.5,
legend_name='Медианный рейтинг заведений по районам',
).add_to(m)
m
Теперь покажем, как на карте распологаются наши заведения. Для этого воспользуемся кластерами.
marker_cluster = MarkerCluster().add_to(m)
def create_clusters(row):
Marker(
[row['lat'], row['lng']],
popup=f"{row['name']} {row['rating']}",
).add_to(marker_cluster)
moscow_places.apply(create_clusters, axis=1)
m
Это замечательный инструмент, который позволяет найти на карте любое заведение, которое мы захотим, однако его практически невозможно корректно отобразить в презентации. К тому же, не всегда корректно можно сделать выводы из полученной информации. Да, мы можем подтвердить, что в ЦАО действительно больше всего заведений, но кластеры не всегда объединяются по административным округам. Они скорее объединяются по близко расположенным маркерам, поэтому данные будут искажены.
Теперь посмотрим, на каких же улицах города расположено больше всего заведений общепита.
#получим таблицу с улицами в разрезе по заведениям
streets = pd.pivot_table(moscow_places, index='street', columns='category', values='name', aggfunc='count')
#Добавим недостающие столбцы
streets['total'] = streets.sum(axis=1)
streets = streets.merge(moscow_places.groupby('street')['chain'].sum().reset_index(),on='street')
streets = streets.merge(moscow_places.groupby('street')['rating'].median().reset_index(),on='street')
streets.sample(5)
| street | бар,паб | булочная | быстрое питание | кафе | кофейня | пиццерия | ресторан | столовая | total | chain | rating | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1149 | улица Буженинова | NaN | NaN | NaN | NaN | NaN | 1.0 | NaN | NaN | 1.0 | 0 | 4.3 |
| 445 | Калужско-Рижская линия | NaN | NaN | NaN | 2.0 | NaN | NaN | 1.0 | NaN | 3.0 | 0 | 4.2 |
| 265 | Большой Симоновский переулок | NaN | NaN | NaN | NaN | 2.0 | NaN | NaN | NaN | 2.0 | 1 | 4.3 |
| 1351 | улица Покровка | 8.0 | 1.0 | 2.0 | 9.0 | 3.0 | 3.0 | 13.0 | 1.0 | 40.0 | 14 | 4.5 |
| 502 | Красноярская улица | NaN | NaN | NaN | NaN | NaN | NaN | 1.0 | NaN | 1.0 | 0 | 4.2 |
#15 первых улиц по общему количеству заведений
top_15_streets = streets.sort_values(by='total', ascending=False).head(15).reset_index(drop=True)
top_15_streets
| street | бар,паб | булочная | быстрое питание | кафе | кофейня | пиццерия | ресторан | столовая | total | chain | rating | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | проспект Мира | 11.0 | 4.0 | 21.0 | 53.0 | 36.0 | 11.0 | 45.0 | 2.0 | 183.0 | 69 | 4.20 |
| 1 | Профсоюзная улица | 6.0 | 4.0 | 15.0 | 35.0 | 18.0 | 15.0 | 26.0 | 3.0 | 122.0 | 55 | 4.30 |
| 2 | проспект Вернадского | 7.0 | 1.0 | 12.0 | 25.0 | 16.0 | 12.0 | 33.0 | 2.0 | 108.0 | 58 | 4.30 |
| 3 | Ленинский проспект | 10.0 | 3.0 | 2.0 | 26.0 | 23.0 | 5.0 | 33.0 | 5.0 | 107.0 | 38 | 4.30 |
| 4 | Ленинградский проспект | 15.0 | 4.0 | 2.0 | 12.0 | 25.0 | 9.0 | 25.0 | 3.0 | 95.0 | 37 | 4.30 |
| 5 | Дмитровское шоссе | 6.0 | 2.0 | 10.0 | 23.0 | 11.0 | 8.0 | 24.0 | 4.0 | 88.0 | 40 | 4.20 |
| 6 | Каширское шоссе | 2.0 | NaN | 10.0 | 20.0 | 16.0 | 5.0 | 19.0 | 5.0 | 77.0 | 44 | 4.20 |
| 7 | Варшавское шоссе | 6.0 | NaN | 7.0 | 18.0 | 14.0 | 4.0 | 20.0 | 7.0 | 76.0 | 27 | 4.20 |
| 8 | Ленинградское шоссе | 5.0 | 2.0 | 5.0 | 13.0 | 13.0 | 3.0 | 26.0 | 3.0 | 70.0 | 31 | 4.30 |
| 9 | МКАД | 1.0 | NaN | 9.0 | 45.0 | 4.0 | NaN | 5.0 | 1.0 | 65.0 | 29 | 4.10 |
| 10 | Люблинская улица | 5.0 | NaN | 5.0 | 26.0 | 11.0 | 1.0 | 10.0 | 2.0 | 60.0 | 23 | 4.30 |
| 11 | улица Вавилова | 2.0 | 2.0 | 11.0 | 15.0 | 10.0 | 3.0 | 12.0 | NaN | 55.0 | 24 | 4.30 |
| 12 | Кутузовский проспект | 2.0 | 1.0 | 2.0 | 14.0 | 13.0 | 3.0 | 16.0 | 3.0 | 54.0 | 23 | 4.35 |
| 13 | улица Миклухо-Маклая | 3.0 | NaN | 4.0 | 21.0 | 4.0 | 2.0 | 15.0 | NaN | 49.0 | 16 | 4.30 |
| 14 | Пятницкая улица | 9.0 | 3.0 | 2.0 | 7.0 | 6.0 | 3.0 | 18.0 | NaN | 48.0 | 24 | 4.40 |
В топ улиц вошли самые длинные улицы, которые являются магистралями или хордами, соединяющие сразу несколько районов, или даже проходящие через половину Москвы. Также, в топ-15 попал МКАД, который опоясывет всю Москву и является границей округов, или даже проходит через них. Но здесь нет никакой ошибки, ведь МКАД также является улицей и на нем также можно встретить многие заведения общепита, включая сетевые. Ничего удивительного в том, что эти улицы попали в топ-15 по количеству заведений.
top_15_streets[['street',
'бар,паб',
'булочная',
'быстрое питание',
'кафе','кофейня',
'пиццерия',
'ресторан',
'столовая']].set_index('street').plot.barh(xlabel='Улица', stacked=True, figsize=(20,10))
plt.xlabel('Количество заведений')
plt.title('Количество заведений в зависимости от типа в разрезе популярных улиц Москвы', fontsize = 20, color='SteelBlue')
plt.show()
По количеству заведений на улицах:
Проспекте Мира - 183. Данный проспект проходит через ЦАО, в котором самое большое скопление заведений общепита, а также через СВАО.Профсоюзная улица, которая соединяет многие крупные районы ЮЗАО.улице Миклухо-Маклая и Пятницкой улице - менее 50 заведений.Теперь рассмотрим, как тип заведения зависит от улицы, на которой оно расположено.
Итак, у нас снова лидируют кафе, за ними идут рестораны, кофейни и в каких-то случаях бары/пабы, а в каких-то - заведения быстрого питания.
Кафе преобладают на улицах: проспект Мира, МКАД, Люблинская улица, Профсоюзная улица, улица Миклухо-Маклая, улица Вавилова и Каширское шоссе.Рестораны лидируют на улицах: Проспект Вернадского, Ленинский проспект, Ленинградское шоссе, Пятницкая улица, Дмитровское шоссе, Варшавское шоссе, Кутузовский проспект.булочные, так их нет на следующих улицах: Каширское шоссе, Варшавское шоссе, МКАД, Люблинская улица и улица Миклухо-Маклая.Проанализируем, сколько у нас улиц, где есть только одно заведение общественного питания.
one_place_street = streets.query('total == 1')
one_place_street
| street | бар,паб | булочная | быстрое питание | кафе | кофейня | пиццерия | ресторан | столовая | total | chain | rating | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1-й Автозаводский проезд | NaN | NaN | NaN | 1.0 | NaN | NaN | NaN | NaN | 1.0 | 1 | 4.2 |
| 1 | 1-й Балтийский переулок | NaN | NaN | NaN | NaN | NaN | NaN | 1.0 | NaN | 1.0 | 0 | 4.4 |
| 2 | 1-й Варшавский проезд | NaN | NaN | NaN | 1.0 | NaN | NaN | NaN | NaN | 1.0 | 0 | 4.0 |
| 3 | 1-й Вешняковский проезд | NaN | NaN | NaN | 1.0 | NaN | NaN | NaN | NaN | 1.0 | 0 | 3.4 |
| 5 | 1-й Голутвинский переулок | 1.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1.0 | 0 | 4.1 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 1436 | улица Шкулёва | NaN | NaN | NaN | NaN | NaN | NaN | 1.0 | NaN | 1.0 | 0 | 4.7 |
| 1437 | улица Шкулёва 4 | NaN | NaN | NaN | NaN | 1.0 | NaN | NaN | NaN | 1.0 | 1 | 4.4 |
| 1439 | улица Шухова | NaN | NaN | NaN | NaN | NaN | NaN | 1.0 | NaN | 1.0 | 0 | 4.1 |
| 1442 | улица Юннатов | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 1.0 | 1.0 | 0 | 4.7 |
| 1447 | № 7 | NaN | NaN | NaN | 1.0 | NaN | NaN | NaN | NaN | 1.0 | 0 | 4.8 |
458 rows × 12 columns
В нашем датасете есть 458 улиц, на которых есть только одно заведение общественного питания. Это примерно 10% от всех улиц Москвы, а также примерно 5% от всех заведений. Большинство этих улиц довольно короткие, часть находится в малонаселенных районах, или индустриальных районах, где спрос на заведения общественного питания невысок.
Проанализируем, какого типа это заведения.
plt.figure(figsize=(15,6))
one_place_street[['бар,паб',
'булочная',
'быстрое питание',
'кафе','кофейня',
'пиццерия',
'ресторан',
'столовая']].sum().sort_values().plot.barh(xlabel='Категория заведения')
plt.xlabel('Количество заведений')
plt.title('Типы единственных заведений на улице', fontsize=20, color='SteelBlue')
plt.show()
Больше всего представлено одиночных кафе - их число превышает 150. Затем идут рестораны и кофейни. После них бары и столовые. Меньше всего одиночных булочных. Впринципе паттерн распределения соответствует общей тенденции и никаких особенностей здесь отметить нельзя.
А что же с сетевыми заведениями?
plt.figure(figsize=(8,8))
one_place_street['chain'].value_counts().plot.pie(autopct='%.0f%%', ylabel='', labels=None)
plt.legend(labels=['Несетевые','Сетевые'])
plt.title('Соотношение сетевых и несетевых заведений', fontsize=20, color='SteelBlue')
plt.show()
Как и ожидалось, здесь также преобладают несетевые заведения - 71%.
Теперь оценим, как распределяется значение среднего чека в зависимости от района.
district_prices = pd.pivot_table(moscow_places, index='district', values='middle_avg_bill', aggfunc='median').reset_index()
district_prices
| district | middle_avg_bill | |
|---|---|---|
| 0 | Восточный административный округ | 575.0 |
| 1 | Западный административный округ | 1000.0 |
| 2 | Северный административный округ | 650.0 |
| 3 | Северо-Восточный административный округ | 500.0 |
| 4 | Северо-Западный административный округ | 700.0 |
| 5 | Центральный административный округ | 1000.0 |
| 6 | Юго-Восточный административный округ | 450.0 |
| 7 | Юго-Западный административный округ | 600.0 |
| 8 | Южный административный округ | 500.0 |
#создадим дополнительную карту, чтобы не было нагромождений
m2 = Map(location=[55.751244, 37.618423], tiles='Cartodb Positron')
#И нанесем на нее хороплет
Choropleth(
geo_data=geo_json,
data=district_prices,
columns=['district', 'middle_avg_bill'],
key_on='properties.name',
fill_color='OrRd',
fill_opacity=0.8,
legend_name='Средний чек заведений по районам',
).add_to(m2)
m2
Судя по данным карты, удаленность от центра Москвы не сильно влияет на стоимость среднего чека. Скорее влияет сам район:
Проанализируем, как чаще всего работают заведения общепита в Москве.
plt.figure(figsize=(8,8))
moscow_places['is_24/7'].value_counts().plot.pie(autopct='%.0f%%', ylabel='', labels=None)
plt.legend(labels=['Не круглосуточные','Круглосуточные'],loc='upper right')
plt.title('Доли заведений по времени работы', fontsize=20, color='SteelBlue')
plt.show()
Всего 9% заведений работают круглосуточно, основная часть заведений работает по расписанию. Проанализируем, заведения какого типа готовы работать круглосуточно.
category_times = pd.pivot_table(data=moscow_places,
index='category',
values=['is_24/7','name'],
aggfunc={'is_24/7':'sum','name':'count'}).reset_index().sort_values(by='name')
category_times['not_24/7'] = category_times['name']-category_times['is_24/7']
ax = category_times.plot(kind='barh',stacked=True, x='category',
y=['not_24/7','is_24/7'], xlabel='Тип заведения', figsize=(15,8))
for i in ax.containers:
ax.bar_label(i,label_type='center')
ax.set_xlabel('Количество заведений')
ax.set_title('Круглосуточные заведения по типу заведения', fontsize=20, color='SteelBlue')
ax.legend(labels=['Не круглосуточные','Круглосуточные']);
Чаще всего, круглосуточно готовы работать в кафе, реже всего круглосуточно работают столовые.
На удивление, среди булочных тоже встречаются круглосуточные заведения, даже чаще, чем среди столовых. Это впечатляет, учитывая особенности работы булочных - обычно они объединены с пекарней и продают свежую выпечку, при круглосуточной работе будет затруднительно постоянно выпекать свежую выпечку.
Выведем все круглосуточные заведения на карту, чтобы посмотреть, где они расположены.
moscow_lat, moscow_lng = 55.751244, 37.618423
# создаём карту Москвы
m3 = Map(location=[moscow_lat, moscow_lng], zoom_start=10, tiles="Cartodb Positron")
# создаём пустой кластер, добавляем его на карту
marker_cluster = MarkerCluster().add_to(m3)
# применяем функцию create_clusters() к каждой строке с круглосуточными заведениями
moscow_places.loc[moscow_places['is_24/7'] == True].apply(create_clusters, axis=1)
# выводим карту
m3
Больше всего круглосуточных заведений расположены в центре города, что ожидаемо, так как там нет ограничений, которые существуют в жилых районах (особенно спальных). Однако, и на переферии города тоже можно утолить голод в любое время суток, просто для этого придётся подольше поискать.
Меньше всего круглосуточных заведений расположено в восточной части города.
Проанализируем, как обстоят дела с заведениями, которые имеют низкий рейтинг. Для начала определим, какой рейтинг стоит считать низким.
moscow_places['rating'].describe()
count 8403.000000 mean 4.229894 std 0.470426 min 1.000000 25% 4.100000 50% 4.300000 75% 4.400000 max 5.000000 Name: rating, dtype: float64
Большая часть заведений в датасете имеет рейтинг больше 4. За низкий рейтинг примем всё, что меньше 4 и проанализируем закономерности для этих заведений.
low_rating = moscow_places.query('rating < 4')
print('В датасете {} заведений с низким рейтингом'.format(len(low_rating)))
В датасете 1169 заведений с низким рейтингом
Всего 14% заведений в датасете имеют рейтинг меньше 4. Посмотрим, какие это заведения.
plt.figure(figsize=(15,6))
sns.barplot(data=low_rating['category'].value_counts().to_frame().reset_index(),
y='index', x='category', orient='h').set(ylabel='Тип заведения',
xlabel='Количество заведений')
plt.title('Распределение заведений с низким рейтингом по категориям',
fontsize=20, color='SteelBlue')
plt.show()
Больше всего заведений с низким рейтингом среди кафе - около половины от всех заведений с рейтингом меньше 4. Меньше всего таких заведений среди булочных. Похоже, что у посетителей более низкие требования к столовым, питейным заведениям, пиццериям и булочным. Этих заведений гораздо меньше среди всех заведений с низким рейтингом.
Теперь оценим, как выглядят средние чеки в таких заведениях и есть ли у них какие-то особенности.
plt.figure(figsize=(15,6))
sns.barplot(data=low_rating.groupby('category')['middle_avg_bill'].median().reset_index().sort_values(by='middle_avg_bill',
ascending=False),
orient='h', y='category', x='middle_avg_bill').set(xlabel='Стоимость среднего чека',
ylabel='Тип заведения')
plt.title('Средний чек заведений с низким рейтингом по категориям',
fontsize=20, color='SteelBlue')
plt.show()
Похоже, что большинство клиентов питейных заведений недовольны стоимостью среднего чека в этих завдениях. Потому что это самые дорогостоящие заведения с низким рейтингом. В остальном серьезных закономерностей здесь выявить не удастся. Мы не знаем что на самом деле послужило причиной таких низких рейтингов. Однако, можно отметить, что поесть в таких заведениях в среднем можно примерно на 500 рублей.
Проанализировав полученную информацию мы можем сделать следующие выводы:
Дополнительно можно выделить следующие интересные особенности:
Перед нами стоит задача помочь основателям фонда «Shut Up and Take My Money» открыть кофейню в Москве, которая будет похожа на кофейню «Central Perk» из сериала «Друзья».
Попробуем узнать, возможно ли это сделать, используя открытые данные, которые предоставляют Яндекс Карты и Яндекс Бизнес. Для этого, получим данные о всех кофейнях, которые есть в Москве.
coffeehouse = moscow_places.query('category == "кофейня"')
print('В датасете представлено {} кофеен'.format(len(coffeehouse)))
В датасете представлено 1413 кофеен
Мы обладаем данными о 1413 кофейнях, теперь рассмотрим их особенности.
plt.figure(figsize=(8,8))
coffeehouse['chain'].value_counts().plot.pie(autopct='%.0f%%', ylabel='', labels=None)
plt.legend(labels=['Несетевые','Сетевые'])
plt.title('Соотношение сетевых и несетевых кофеен', fontsize=20, color='SteelBlue')
plt.show()
В Москве работает почти поровну сетевых и несетевых кофеен, однако преобладают несетевые. В первую очередь нас конечно интересуют несетевые кофейни, так как кофейня в сериале "Друзья" не была сетевой. Да и открывать сразу сетевое заведение и ожидать, что оно станет таким же крутым, как в сериале - нецелесообразно. Поэтому рассмотрим только несетевые заведения.
coffeeshops = coffeehouse.query('chain == 0')
print('Исследуем закономерности для {} несетевых кофеен'.format(len(coffeeshops)))
Исследуем закономерности для 693 несетевых кофеен
district_coffee = pd.pivot_table(coffeeshops,
index='district',
values=['name','rating','middle_coffee_cup','is_24/7'],
aggfunc={'name':'count',
'rating':'median',
'middle_coffee_cup':'median',
'is_24/7':'sum'}).reset_index()
district_coffee
| district | is_24/7 | middle_coffee_cup | name | rating | |
|---|---|---|---|---|---|
| 0 | Восточный административный округ | 0 | 135.0 | 54 | 4.40 |
| 1 | Западный административный округ | 1 | 170.0 | 57 | 4.30 |
| 2 | Северный административный округ | 0 | 165.0 | 96 | 4.40 |
| 3 | Северо-Восточный административный округ | 0 | 162.5 | 80 | 4.35 |
| 4 | Северо-Западный административный округ | 0 | 165.0 | 28 | 4.45 |
| 5 | Центральный административный округ | 6 | 195.0 | 207 | 4.40 |
| 6 | Юго-Восточный административный округ | 0 | 150.0 | 60 | 4.35 |
| 7 | Юго-Западный административный округ | 2 | 190.5 | 46 | 4.40 |
| 8 | Южный административный округ | 0 | 170.0 | 65 | 4.40 |
plt.figure(figsize=(15,6))
sns.barplot(data=district_coffee.sort_values(by='name',ascending=False),
y='district',
x='name',
orient='h').set(xlabel='Количество заведений',ylabel='Округ')
plt.title('Распределение кофеен по административным округам Москвы', fontsize=20, color='SteelBlue')
plt.show()
Больше всего кофеен в ЦАО и САО. Меньше всего кофеен в Северно-Западном административном округе. Конечно, если заказчик не боится конкуренции и хочет создать доступную кофейню, то стоит открывать кофейню ближе к центру столицы. Однако, не стоит забывать, что кофейня "Central Perk" была расположена рядом с парком. Таким образом, стоит рассматривать Северо-Восточный и Юго-Западный административные округа. Так как в них не так много кофеен, как например в ЦАО и очень много парков и скверов. А также достаточно развитая сеть транспорта, так что пункт с доступностью точно будет выполнен.
Теперь оценим, как же работают кофейни в Москве.
plt.figure(figsize=(8,8))
coffeeshops['is_24/7'].value_counts().plot.pie(autopct='%.0f%%', ylabel='', labels=None)
plt.legend(labels=['Не круглосуточные','Круглосуточные'])
plt.title('Доли кофеен по времени работы', fontsize=20, color='SteelBlue')
plt.show()
Большинство кофеен (99%) работает не круглосуточно, интересующая нас кофейня также не работала круглосуточно. К тому же круглосуточная работа накладывает некоторые ограничения и трудности, как работникам, так и хозяевам заведений. Но, если есть желание, сделать что-то более особенное - то можно попробовать создать круглосуточную кофейню.
Теперь перейдем к оценке рейтингов кофеен в зависимости от их расположения.
#создадим дополнительную карту, чтобы не было нагромождений
m4 = Map(location=[55.751244, 37.618423], tiles='Cartodb Positron')
#И нанесем на нее хороплет
Choropleth(
geo_data=geo_json,
data=district_coffee,
columns=['district', 'rating'],
key_on='properties.name',
fill_color='YlGn',
fill_opacity=0.8,
legend_name='Средний рейтинг кофеен по районам',
).add_to(m4)
m4
Самые высокие рейтинги у кофеен, расположенных в Северо-Западном административном округе. Еще один плюс к выбору этого района, однако придется держать высокую планку, чтобы соревноваться с другими кофейнями в этом районе. Самые низкие рейтинги в Западном административном округе, похоже здесь самые требовательные посетители.
А как расположение кофейни влияет на цену.
m5 = Map(location=[55.751244, 37.618423], tiles='Cartodb Positron')
#И нанесем на нее хороплет
Choropleth(
geo_data=geo_json,
data=district_coffee,
columns=['district', 'middle_coffee_cup'],
key_on='properties.name',
fill_color='PuBu',
fill_opacity=0.8,
legend_name='Средняя стоимость чашки кофе по районам',
).add_to(m5)
m5
А вот самая дорогая чашка кофе ждет посетителей в Центральном и Юго-Западном административных округах. Дешевле всего выпить кофе в Восточном административном округе. Возможно здесь не так сильно ценят кофе. Да и вообще в восточной части города средня цена чашки кофе не превышает 155 рублей.
Конечно выгоднее открывать кофейню с высокими ценами, а для этого необходимо делать это там, где такая цена будет оправдана. Также, высокая цена чашки кофе может быть связана с высокой ценой аренды помещения в этом районе. И скорее всего в ЦАО так и есть. Однако, в ЮЗАО аренда скорее всего будет значительно ниже. Так что пока ЮЗАО выглядит как наиболее привлекательный район.
Исходя из небольшого исследования, которое мы провели, можно сделать вывод, что основателям фонда «Shut Up and Take My Money» вполе удастся создать кофейню мечты.
Для того, чтобы открыть такую же кофейню, как "Central Perk", стоит придерживаться следующих идей:
Согласно тем данным, которые мы имеем:
Конечно, успех кофейни зависит не только от удачного расположения и финансовых аспектов, сколько от удовлетворенности посетителей. Да, эти рекомендации решают часть проблем, но только от руководства кофейни будет зависеть, станет ли она такая же популярная и успешная, как "Central Perk".